#ifndef gui_h
#define gui_h

#include "main.h"
#include "word.h"

extern "C"
{
    extern void *pvPortMalloc(size_t xWantedSize);
    extern void vPortFree(void *pv);
}

inline uint16_t rgb565(uint8_t r, uint8_t g, uint8_t b)
{
    return (uint16_t)r >> 3 << 11 | (uint16_t)g >> 2 << 5 | (uint16_t)b >> 3;
}

enum color_type
{
    _1bit_color_type,
    _565_color_type
};

enum widget_type
{
    window_type,
    other_type
};

//只需改动以下三行
const color_type color_type_ = _565_color_type; //设置颜色模式
const uint16_t main_window_width_ = 240;
const uint16_t main_window_height_ = 320; //所有的坐标系将以这个为准 //坐标以左上角为原点（0,0），x向右递增，y向下递增
const uint8_t origin_ = 0;                //仅用于代替坐标原点的0

class window
{
protected:
    void *display_buffer_;                           //要注意这是void类型的数组，对其元素取值/赋值时要转换类型，并且类型必须要对
    uint8_t widget_type_ = window_type;

    int16_t x_, y_;           //窗口的起点（相对于父窗口）
    uint16_t width_, height_; //窗口宽高，单位是像素。>=1
    static window *main_window_;
    static window *desktop_window_;                         //主窗口地址，桌面窗口地址
    window *previous_ = nullptr, *next_ = nullptr;          //同级窗口之间的联系。也是绘制顺序，previou比next先绘制。选中的窗口会被移动到最后面，则该窗口必定覆盖在其它窗口上
    window *first_child_ = nullptr, *last_child_ = nullptr; //第一个和最后一个child
    window *parent_ = nullptr;                              //父窗口
    static uint8_t creat_main_window_flag_;                 //主窗口是否建立的标志

    window *derived_ = nullptr;        //派生类的地址，这样就可以通过window类就能控制各种派生类了
    static int16_t mouse_x_, mouse_y_; //鼠标的绝对位置
    static uint8_t mouse_status_;      //鼠标的状态
    static window *focus_window_;      //获得焦点的窗口

    static void draw_main_window_pixel(uint16_t x, uint16_t y, uint32_t color);                                                             //在主窗口里画点
    void updata_my_window(uint16_t display_x, uint16_t display_y, uint16_t display_width, uint16_t display_height, uint16_t x, uint16_t y); //更新自己的窗口
    uint8_t calculate_overlap_range(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t &p_sta_x, uint16_t &p_sta_y, uint16_t &my_sta_x, uint16_t &my_sta_y, uint16_t &my_width, uint16_t &my_height);
    inline window *get_focus_in_window(int16_t x, int16_t y); //返回焦点在哪个窗口上
    static void move_focus_initial_window_to_last(void);      //将焦点窗口所在的初始窗口移到关系树的最右边
    static void run_action(void);                             //运行动作函数
    void set_derived(window *derived) { derived_ = derived; }
    void set_widget_type(widget_type widget_type) { widget_type_ = widget_type; }
    virtual void action(void) {} //动作函数，派生类将重写这个函数，然后被基类调用

public:
    window(int16_t x = 0, int16_t y = 0, uint16_t width = main_window_width_, uint16_t height = main_window_height_);
    virtual ~window();

    void connect(window *parent);                                                             //连接父窗口。跟在父窗口最后一个同级窗口右边。自己就成了该窗口的子窗口
    void disconnect(void);                                                                    //与窗口关系树断开连接
    static void set_fill_srceen_pt(void (*fill_srcee)(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t *data));
    static void updata_all_window(void);                                                      //更新所有窗口
    static void in_which_window(uint16_t x, uint16_t y, uint8_t status, uint8_t pattern = 0); //pattern=0，为鼠标模式，为1是绝对坐标模式

    inline void draw_pixel(uint16_t x, uint16_t y, uint32_t color);
    inline uint32_t get_pixel(uint16_t x, uint16_t y); //获取点的颜色
    void draw_frame(void);                             //填充窗口边缘
    void fill(uint32_t color);                         //填充

    int16_t get_x(void) { return x_; }
    int16_t get_y(void) { return y_; }
    int16_t get_x2(void) { return x_ + width_ - 1; }
    int16_t get_y2(void) { return y_ + height_ - 1; }
    uint16_t get_width(void) { return width_; }
    uint16_t get_height(void) { return height_; }
    static uint16_t get_main_window_width(void) { return main_window_width_; }
    static uint16_t get_main_window_height(void) { return main_window_height_; }
    window *get_parent(void) { return parent_; }
    window *get_derived(void) { return derived_; }

    static void *get_main_window_display_buffer(void) { return main_window_->display_buffer_; } //使用这个时一定要加上类型转换，例(uint16_t *)window::get_screen_display_buffer()
    static uint8_t get_mouse_status(void) { return mouse_status_; }
    void get_mouse_relative_me_xy(int16_t &x, int16_t &y);        //获取鼠标相对于自己窗口的位置
    void get_window_absolute_coordinates(int16_t &x, int16_t &y); //获取自己窗口的绝对位置
    void move_window(int16_t x, int16_t y) { x_ = x, y_ = y; }    //直接更改窗口的起始位置
};
void window::draw_pixel(uint16_t x, uint16_t y, uint32_t color)
{
    if (x >= width_ || y >= height_)
        return;

    if (color_type_ == _1bit_color_type)
    {
        uint16_t addr = y / 8 * width_ + x;
        uint8_t src = ((uint8_t *)display_buffer_)[addr];
        color ? src = (0x01 << (y % 8)) | src : src = (~(0x01 << (y % 8))) & src;
        ((uint8_t *)display_buffer_)[addr] = src;
    }
    else
        ((uint16_t *)display_buffer_)[y * width_ + x] = color;
}

uint32_t window::get_pixel(uint16_t x, uint16_t y)
{
    if (color_type_ == _1bit_color_type)
        return (0x01 << (y % 8) & ((uint8_t *)display_buffer_)[y / 8 * width_ + x]) ? 1 : 0;
    else
        return ((uint16_t *)display_buffer_)[y * width_ + x];
}

class button : public window
{
private:
    uint8_t status = false;

public:
    button(window *win, const char *str, int16_t x, int16_t y, uint16_t width, uint16_t height);
    virtual void action(void); //更新按钮的状态
    uint8_t get_status(void) { return status; }
};

class toolbar : public window
{
public:
    toolbar(window *win, uint16_t height, const char *str = "");
    virtual void action(void); //移动父窗口
};

class windowss : public window//对核心再包装，一次性完成窗口和工具栏等基础控件的创建。并保证不影响其它功能
{
private:
    static const uint8_t toolbar_height_ = 5;
    toolbar *toolbar_ = nullptr;
    window *draw_window_ = nullptr;

public:
    //高度只代表除工具栏的部分的高度
    windowss(window *win = nullptr, int16_t x = 0, int16_t y = 0, uint16_t width = main_window_width_, uint16_t height = main_window_height_, uint8_t creat_toolbar = true);
    ~windowss();
    virtual void action(void) {}
    window *get_draw_window(void) { return draw_window_ ? draw_window_ : this; } //如果有工具栏，那么绘图窗口将重建一个新的窗口用来给用户绘图，原来的部分只能用作背景
};

//输入法
// class input_method_editor : public window
// {
// public:

// };

#endif